package org.osflash.signals;

import asunit.asserts.AssertEquals;

class PrioritySignalTest extends ISignalTestBase {

	var prioritySignal : IPrioritySignal;
	var gotListenerDispatchOrder : Array<Dynamic>;
	@:meta(Before())
	public function setUp() : Void {
		gotListenerDispatchOrder = [];
		prioritySignal = new PrioritySignal();
		signal = prioritySignal;
	}

	@:meta(After())
	override public function destroySignal() : Void {
		gotListenerDispatchOrder = null;
		prioritySignal.removeAll();
		prioritySignal = null;
		signal = null;
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_3() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_4() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_5() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_6() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.addWithPriority(listenerB, 2);
		prioritySignal.addWithPriority(listenerA, 3);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_3() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_4() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_5() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_unconsecutive_6() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, 5);
		prioritySignal.addWithPriority(listenerB, 10);
		prioritySignal.addWithPriority(listenerA, 20);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_3() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_4() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_5() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_higher_priority_should_be_called_first_independant_of_order_added_even_if_negative_6() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, -3);
		prioritySignal.addWithPriority(listenerB, -2);
		prioritySignal.addWithPriority(listenerA, -1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_same_priority_should_be_called_in_order_added_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerA, 1);
		prioritySignal.addWithPriority(listenerB, 1);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_same_priority_should_be_called_in_order_added_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [B, A, C];
		prioritySignal.addWithPriority(listenerB, 1);
		prioritySignal.addWithPriority(listenerA, 1);
		prioritySignal.addWithPriority(listenerC, 1);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_priority_zero_should_be_called_in_order_added_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [B, C, A];
		prioritySignal.add(listenerB);
		prioritySignal.add(listenerC);
		prioritySignal.add(listenerA);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_priority_zero_should_be_called_in_order_added_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [C, B, A];
		prioritySignal.add(listenerC);
		prioritySignal.add(listenerB);
		prioritySignal.add(listenerA);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_priority_zero_should_be_called_after_high_and_before_negative_1() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, -10);
		prioritySignal.add(listenerB);
		prioritySignal.addWithPriority(listenerA, 10);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	@:meta(Test())
	public function listeners_added_with_priority_zero_should_be_called_after_high_and_before_negative_2() : Void {
		var expectedListenerDispatchOrder : Array<Dynamic> = [A, B, C];
		prioritySignal.addWithPriority(listenerC, -10);
		prioritySignal.addWithPriority(listenerA, 10);
		prioritySignal.add(listenerB);
		prioritySignal.dispatch();
		assertArrayEqual(expectedListenerDispatchOrder, gotListenerDispatchOrder);
	}

	function listenerA() : Void {
		gotListenerDispatchOrder.push(A);
	}

	function listenerB() : Void {
		gotListenerDispatchOrder.push(B);
	}

	function listenerC() : Void {
		gotListenerDispatchOrder.push(C);
	}

	function assertArrayEqual(expected : Array<Dynamic>, got : Array<Dynamic>) : Void {
		assertEquals("array length unequal", expected.length, got.length);
		var i : Int = 0;
		while(i < gotListenerDispatchOrder.length) {
			assertEquals("@i=" + i, expected[i], got[i]);
			i++;
		}
	}

	static var A : String = "A";
	static var B : String = "B";
	static var C : String = "C";
	static var D : String = "D";
	static var E : String = "E";
}

